<template>
  <section ref="section" class="section" style="margin-bottom: 30px;">
  	<div ref="workarea" class="workarea" style="width: 150%; height: 150%;">
  		<svg ref="svg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"
  			xmlns:xlink="http://www.w3.org/1999/xlink"
  			style="background-image: url()">
  			<flow-defs/>
  			<g class="temp">
          <g class="line" v-show="temp.show">
            <polyline stroke="#1296db" 
              stroke-width="2" 
              stroke-linecap="round" 
              marker-end="url(#arrow)" 
              fill="none" 
              class="line" 
              stroke-dasharray="5,5" 
              :points="temp.points"></polyline>
          </g>
        </g>
  			<g class="nodes">
          <flow-node v-for="(node, idx) in nodes"
            :node="node"
            :key="node.id"
            :idx="idx"
            :setNodeDotCls="setNodeDotCls"
            :moveNode="moveNode"
            :resetNode="resetNode"
            :delNode="delNode"
            :showNodeRemove="showNodeRemove"
            :setNodeTitle="setNodeTitle"
            :setMenu="setMenu"
            @onDblclick="onDblclick"
          />
        </g>
  			<g class="lines">
          <flow-line v-for="(line, idx) in lines"
            :line="line"
            :key="line.id"
            :idx="idx"
            :setLineTool="setLineTool"
          />
        </g>
  			<g class="nodeDot"
          v-show="nodeDot.show"
          :transform="`translate(${nodeDot.translate})`"
          @mouseover="nodeDot.show = true"
          @mouseout="nodeDot.show = false"
          >
          <rect @mousedown="dotMouseDown(nodeDot.translate, 'top')"
            @mouseup="addLine(nodeDot.translate, 'top')"
            rx="2" x="18" y="-6"></rect>
          <rect @mousedown="dotMouseDown(nodeDot.translate, 'right')"
            @mouseup="addLine(nodeDot.translate, 'right')"
            rx="2" x="42" y="18"></rect>
          <rect @mousedown="dotMouseDown(nodeDot.translate, 'bottom')"
            @mouseup="addLine(nodeDot.translate, 'bottom')"
            rx="2" x="18" y="42"></rect>
          <rect @mousedown="dotMouseDown(nodeDot.translate, 'left')"
            @mouseup="addLine(nodeDot.translate, 'left')"
            rx="2" x="-6" y="18"></rect>
        </g>
      </svg>
  		<div class="linetool"
        v-show="lineTool.show"
        :style="lineTool.style"
        >
  			<div>
  				<b class="dashed" @mousedown="changeLineType('dashed')"></b>
  				<b class="line" @mousedown="changeLineType('line')"></b>
          <b class="polyline" @mousedown="changeLineType('polyline')"></b>
          <b class="remove" @mousedown="delLine"></b>
  			</div>
  		</div>
      <flow-menu
        ref="menu"
        :delNode="delNode"
        :onSettingNode="onSettingNode"
      />
  		<div class="ipt"
        v-show="ipt.show"
        :style="ipt.style"
        @mousedown.stop="()=>{return false}"
        >
  			<input type="text" class="text" maxlength="10" v-model="ipt.value">
        <b class="ok" @mousedown.stop="setNodeTitle(false)"></b>
  		</div>
  	</div>
    <a ref="imageLink" :download="downloadName" style="display: none" :href="imgUrl"></a>
    <div style="display: none"><canvas ref="canvas"></canvas></div>
  </section>
</template>

<script>
  import FlowDefs from './FlowDefs'
  import FlowNode from './FlowNode'
  import FlowLine from './FlowLine'
  import FlowMenu from './FlowMenu'
  import flow from './js/flow'
  import language from './js/lang/smtflow.i18n.zh-cn'
  export default {
    name: 'FlowSection',
    props: [
      'title',
      'lineType',
      'initFlowData',
      'onRemoveNode',
      'onSettingNode',
      'onDblclick',
      'onAddNode',
      'onAddLine'
    ],
    data(){
      return {
        nodes: [],
        lines: [],
        temp: {
          points: [],
          show: false,
          from: {
            id: null,
            points: [],
            dotType: '',
            nodePos: {},
            dotPos: {}
          }
        },
        nodeDot: {
          show: false,
          translate: [-1000, -1000],
          nodeId: null
        },
        lineTool: {
          show: false,
          style: {},
          idx: -1
        },
        ipt: {
          show: false,
          style: {},
          idx: -1,
          value: ''
        },
        imgUrl: '',
        downloadName: ''
      }
    },
    methods: {
      addNode(node, coor) {
        this.onAddNode(node.type);
        let woft = this.$refs.workarea.getBoundingClientRect();
        if(coor.x > woft.left
          && coor.y > woft.top
          && coor.x < (woft.width + woft.left)
          && coor.y < (woft.height + woft.top)) {

          let x = coor.x - woft.left - flow.$nodeWidth / 2;
          let y = coor.y - woft.top - flow.$nodeHeight / 2;

          let scope = flow.$nodeXyScope(woft, x, y);          
          node.translate = [Math.floor(scope.x * 100) / 100, Math.floor(scope.y * 100) / 100]
          let idx = (this.nodes.push(node) - 1);
          this.setNodeDotCls(true, idx);
        }
      },
      setNodeDotCls(show, idx, nodeId) {
        this.nodeDot.show = show;
        if(show) {
          this.nodeDot.translate = this.nodes[idx].translate;
          this.nodeDot.nodeId = nodeId;
        }
      },
      showNodeRemove(idx, show) {
        this.nodes[idx].showRemove = show;
      },
      moveNode(idx, nodeId) {        
        let $w = window;
        let $v = this;
        let node = this.nodes[idx];
        function nodeMove(e) {
          node.showRemove = false;
	  	    node.cls.indexOf('move') == -1? node.cls.push('move'): null
          $v.nodeDot.show = false;
					let x = (e.offsetX - flow.$nodeWidth / 2);
					let y = (e.offsetY - flow.$nodeHeight / 2);
          let woft = $v.$refs.workarea.getBoundingClientRect();
					let scope = flow.$nodeXyScope(woft, x, y);
          $v.nodes[idx].translate = [scope.x, scope.y]
          flow.$changeLinePoints($v.lines, nodeId, scope);
				}
        $v.$refs.svg.addEventListener('mousemove', nodeMove)
        
        $w.onmouseup = function() {
          node.showRemove = true;
          $v.setNodeDotCls(true, idx, node.id); 
          node.cls = node.cls.filter((val) => val !== 'move')
          $v.$refs.svg.removeEventListener('mousemove', nodeMove);
          $w.onmouseup = null;
        };
      },
      resetNode(idx) {
        this.nodes.forEach((node, i) => node.cls = (typeof idx !== undefined && idx == i)? ['focus']: []);
      },
      dotMouseDown(translate, dotType) {
        let $w = window;
        let $v = this;
        let woft = this.$refs.workarea.getBoundingClientRect();
        let id = this.nodeDot.nodeId;
        let nodePos = {x: translate[0], y: translate[1]};
        let dotPos = flow.$dotPos(dotType, nodePos);
        let points = [dotPos.x, dotPos.y];
        this.temp.from = {id, points ,dotType, nodePos, dotPos};

        function svgMousemove(me) {
          $v.temp.show = true;
          let x = me.clientX - woft.left;
					let y = me.clientY - woft.top;
          let tempPoints = points.concat([x, y]);
          $v.temp.points = tempPoints
        }
        $w.addEventListener('mousemove', svgMousemove);
        $w.onmouseup = function() {
          $w.onmouseup = null;
          $w.removeEventListener('mousemove', svgMousemove);
          if($v.temp.show) $v.temp = $v.$options.data().temp;
        }
      },
      addLine(translate, toDot) {
        if(this.temp.show) {
          let from = this.temp.from;
          if(from.id !== this.nodeDot.nodeId) {
            let linkLine = this.lines.filter((line) => line.from.id === from.id && line.to.id === this.nodeDot.nodeId)
            if(linkLine.length > 0) {
              this.setMessage(language.msg.nodesAreConnected);
            }
            else {
              this.onAddLine(from.id, this.nodeDot.nodeId);
              let fromDot = from.dotType;
              let fromNodePos = from.nodePos;
              let fromDotPos = from.dotPos;
              let fromPoints = from.points;

              let toNodePos = {x: translate[0], y: translate[1]};
              let toDotPos = flow.$dotPos(toDot, toNodePos);
              let toPoints = [toDotPos.x, toDotPos.y];

              let type = this.lineType;
              let linePamams = {
                type, fromPoints, toPoints, fromDot, toDot, fromNodePos, toNodePos
              }
              let points = flow.$linePoints(linePamams);
              this.lines.push({id: flow.$getId(), dasharray: false, points, type, cls:[], from: {
                id: from.id,
                dot: fromDot,
                nodePos: fromNodePos,
                ... fromDotPos
              }, to: {
                id: this.nodeDot.nodeId,
                dot: toDot,
                nodePos: toNodePos,
                ... toDotPos
              }})
            }
          }
        }
      },
      delNode(nodeId, idx) {
        let type = this.nodes[idx].type;
        if(this.onRemoveNode) {
          window.setTimeout(()=>{
            if(this.onRemoveNode(nodeId, type)) {              
              this.nodeDot.show = false;
              this.nodes.splice(idx, 1);
              this.lines = this.lines.filter(line => line.from.id != nodeId && line.to.id != nodeId)
            }
          },0);
        }
      },
      setLineTool(lineTool) {
        if(lineTool.show) {
          this.lineTool = lineTool;
          this.lines[this.lineTool.idx].cls.push('focus')
        }
        else {
          this.lineTool.show = false;
          this.lineTool.style = [];
        }
      },
      delLine() {
        this.lines.splice(this.lineTool.idx, 1);
        this.lineTool = this.$options.data().lineTool;
      },
      changeLineType(lineType) {
        let line = this.lines[this.lineTool.idx];
        if(lineType === 'dashed') {
          line.dasharray = !line.dasharray;
        }
        else {
          line.type = lineType;
          let lineParams = {
            type: line.type,
            fromDot: line.from.dot,
            fromPoints: [line.from.x, line.from.y],
            fromNodePos: line.from.nodePos,
            toDot: line.to.dot,
            toPoints: [line.to.x, line.to.y],
            toNodePos: line.to.nodePos
          }
          line.points = flow.$linePoints(lineParams);
        }
      },
      setNodeTitle(node, style) {
        this.ipt.show = node ? true: false;
        this.ipt.style = style || {};
        if(node) {
          this.ipt.value = this.nodes[node.idx].title;
          this.ipt.idx = node.idx;
        }
        else {
          this.nodes[this.ipt.idx].title = this.ipt.value;
          this.ipt = this.$options.data().ipt;
        }
      },
      setMenu(node, style) {
        this.$refs.menu.setMenu(node, style);
      },
      resetWorkarea(noMsg) {
        this.nodes = [];
        this.lines = [];
        this.temp = this.$options.data().temp;
        this.nodeDot = this.$options.data().nodeDot;
        this.lineTool = this.$options.data().lineTool;        
        this.ipt = this.$options.data().ipt;
        !noMsg ? this.setMessage(language.msg.workspaceReset) : null;
        this.initFlowData();
      },
      getFlowData(callback) {
        let data = flow.$getData(this.nodes, this.lines);        
        data = Object.assign({
          title: this.title,
          lineType: this.lineType
        }, data);
        return callback(data);
      },
      loadFlowData(dataJson) {
        if(!dataJson) return;
        this.resetWorkarea('noMsg');
        let data = JSON.parse(dataJson);
        this.initFlowData({
          title: data.title,
          lineType: data.lineType
        });
        this.nodes = data.nodes.map(node => {
          let newNode = Object.assign(node, {
                          translate: [node.x, node.y],
                          cls: [],
                          showRemove: false,
                          image: require('./css/icons/tool-' + node.type + '.svg')
                        });
          return newNode;
        });
        this.lines = data.lines.map(line => {
          let newLine = Object.assign(line, {cls: []});
          return newLine;
        });
      },
      downLoad() {
        let offset = this.$refs.workarea.getBoundingClientRect();
        let options = {width: offset.width, height: offset.height};
        let svg = this.$refs.svg.cloneNode(true);
        svg.setAttribute('width', options.width);
        svg.setAttribute('height', options.height);
        let source = new XMLSerializer().serializeToString(svg);
				let base64 = 'data:image/svg+xml;base64,' + window.btoa(flow.$reEncode(source));				
				let image = new Image();
				image.src = base64;
				image.onload = () => {
					let dataUrl = flow.$getDataURL(this.$refs.canvas, this.title, image, options);
          this.downloadName = this.title + '.png';
          this.imgUrl = dataUrl;
          setTimeout(() => {
            this.$refs.imageLink.click();
            this.downloadName = '';
            this.imgUrl = '';
          }, 0);
				}
      }
    },
    components: {
      FlowDefs, FlowNode, FlowLine, FlowMenu
    },
    mounted() {
      this.$flow.$on('addNode', this.addNode)
      this.$flow.$on('resetWorkarea', this.resetWorkarea)
      this.$flow.$on('getFlowData', this.getFlowData)
      this.$flow.$on('loadFlowData', this.loadFlowData)
      this.$flow.$on('downLoad', this.downLoad)

      window.addEventListener('mousedown', () => {
        this.ipt.show ? this.setNodeTitle(false) : null;
        this.setMenu(false);
      });
      window.addEventListener('mousedown', () => {
        this.resetNode();
        this.lineTool.show ?this.setLineTool({show: false}): null;
        this.lines.map(line => line.cls = []);
      }, true)
    },
    beforeDestroy() {
      this.$flow.$off(['addNode',
        'resetWorkarea',
        'getFlowData',
        'loadFlowData',
        'downLoad'
      ]);
    }
  }
</script>

<style scoped>
  ::-webkit-scrollbar {
      width: 10px;
      height: 10px;
  }
  ::-webkit-scrollbar-track-piece {
      background-color: #CCCCCC;
  }
  ::-webkit-scrollbar-thumb:vertical {
      height: 6px;
      background-color: #999999;
      border-radius: 6px;
  }
  ::-webkit-scrollbar-thumb:horizontal {
      width: 6px;
      background-color: #999999;
      border-radius: 6px;
  }
  ::-webkit-scrollbar-thumb:hover {
      background-color:#9f9f9f;
  }
  ::-webkit-scrollbar-corner {
    background-color: #CCCCCC;
  }
  div.workarea {
    position: relative;
  }
  div.workarea.focus {	
    cursor: move;
  }
  div.ipt {
    position: absolute;
    z-index: 1500;
    background-color: #d2e1f0;
    padding: 2px;
    border: 1px #ccc solid;
    border-radius: 3px;
  }
  div.ipt > input.text {
    float: left;
    width: 80px;
    outline: none;
    text-align: center;
    font-size: 12px;
  }
  div.ipt > b.ok {
    float: left;
    width: 20px;
    height: 20px;
    background-size: 20px 20px;
    border: 0;
    background-repeat: no-repeat;
    background-position: center;
    background-image:url(./css/img/icon-ok.svg);
  }
  div.ipt > b.ok:hover {
    background-color: #e3ea8f;
    cursor: pointer;
  }
  section.section {
    border: #99b1ce 1px solid;
    border-radius: 3px;
    position: absolute;
    top: 50px;
    left: 74px;	
    right: 5px;
    bottom: 5px;
    overflow: auto;
    box-sizing: border-box;
  }
	.nodeDot rect {
		width: 10px;
		height: 10px;
		fill: transparent;
		stroke-width: 2;
		stroke: transparent;
		fill-opacity: 0.5;
	}
	.nodeDot rect {
		cursor: pointer;
		fill: #838383;
	}
  .nodeDot rect:hover {
		fill: #ede6b7;
		stroke: #838383;
		stroke-width: 2;
	}
  
  div.linetool {
    position: absolute;
    z-index: 1000;
    top: 0;
    left: 0;
    width: 80px;
    height: 20px;
    border: 1px solid #CCC;
    background-color: #e3e2e2;
  }
  div.linetool b {
    width: 20px;
    height: 20px;
    box-sizing: border-box;	
    background-size: 20px 20px;
  }
  div.linetool b:hover {
    opacity: 0.7;
    cursor: pointer;
    background-color: #ede6b7;
  }
  div.linetool b.dashed {
    background-image:url(./css/img/line-dashed.svg);	
  }
  div.linetool b.line {
    background-image:url(./css/img/line-line.svg);	
  }
  div.linetool b.polyline {
    background-image:url(./css/img/line-polyline.svg);	
  }
  div.linetool b.remove {
    background-image:url(./css/img/line-remove.svg);	
  }
  div.linetool > div > b {
    display: inline-block;
    border: 0;
    background-repeat: no-repeat;
    background-position: center;
  }
</style>